package com.yudean.esb.util;

import com.yudean.esb.cached.CacheException;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.Element;
import net.sf.ehcache.config.CacheConfiguration;
import net.sf.ehcache.store.MemoryStoreEvictionPolicy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

/**
 * 采用ehcache实现的一个简单的对象缓存池，采取LRU规则
 *
 * @author Lei Duan <duanlei#gdyd.com>
 * @version 1.0.0
 * @since 2013-10-30@15
 */
public class ObjectPooledFactoy {
    private static final Logger LOGGER = LoggerFactory
            .getLogger(ObjectPooledFactoy.class);
    private static Ehcache cache;

    private static void init() {
        LOGGER.info("init a object pool factory");
        CacheManager manager = CacheManager.getInstance() == null ? CacheManager
                .create() : CacheManager.getInstance();
        // Create a Cache specifying its configuration.
        cache = new Cache(new CacheConfiguration("objectCache", 30)
                .memoryStoreEvictionPolicy(MemoryStoreEvictionPolicy.LFU)
                .overflowToDisk(true).eternal(false).timeToLiveSeconds(60)
                .timeToIdleSeconds(30).diskPersistent(true)
                .diskExpiryThreadIntervalSeconds(0));

        manager.addCache(cache);
        if (cache == null)
            throw new RuntimeException("必须在ehcache中配置好objectCache以获得更好的系统性能！");
    }

    /**
     * Puts an object into the cache.
     *
     * @param key   a key
     * @param value a value
     * @throws CacheException if the {@link net.sf.ehcache.CacheManager} is shutdown or
     *                        another {@link Exception} occurs.
     */
    public static void put(Object key, Object value) throws CacheException {
        if (cache == null) {
            init();
        }
        try {
            LOGGER.info("put():adding a object-{key:{}}", key);
            Element element = new Element(key, value);
            cache.put(element);
        } catch (IllegalArgumentException e) {
            throw new CacheException(e);
        } catch (IllegalStateException e) {
            throw new CacheException(e);
        } catch (net.sf.ehcache.CacheException e) {
            throw new CacheException(e);
        }
    }

    /**
     * Puts an object into the cache.
     *
     * @param key   a key
     * @param value a value
     * @throws CacheException if the {@link net.sf.ehcache.CacheManager} is shutdown or
     *                        another {@link Exception} occurs.
     */
    public static void update(Object key, Object value) throws CacheException {
        put(key, value);
    }

    /**
     * Gets a value of an element which matches the given key.
     *
     * @param key the key of the element to return.
     * @return The value placed into the cache with an earlier put, or null if
     * not found or expired
     * @throws CacheException
     */
    public static <T> T get(Object key) throws CacheException {
        if (cache == null) {
            init();
        }
        try {
            if (key == null)
                return null;
            else {
                Element element = cache.get(key);
                if (element != null)
                    return (T) element.getObjectValue();
            }
            return null;
        } catch (net.sf.ehcache.CacheException e) {
            throw new CacheException(e);
        }
    }

    /**
     * Removes the element which matches the key.
     * <p/>
     * If no element matches, nothing is removed and no Exception is thrown.
     *
     * @param key the key of the element to remove
     * @throws CacheException
     */
    public static void remove(Object key) throws CacheException {
        if (cache == null) {
            init();
        }
        try {
            cache.remove(key);
        } catch (IllegalStateException e) {
            throw new CacheException(e);
        } catch (net.sf.ehcache.CacheException e) {
            throw new CacheException(e);
        }
    }

    /**
     * Remove all elements in the cache, but leave the cache in a useable state.
     *
     * @throws CacheException
     */
    public static void clear() throws CacheException {
        if (cache == null) {
            init();
        }
        try {
            cache.removeAll();
        } catch (IllegalStateException e) {
            throw new CacheException(e);
        } catch (net.sf.ehcache.CacheException e) {
            throw new CacheException(e);
        }
    }

    @SuppressWarnings("rawtypes")
    public static List keys() throws CacheException {
        return cache.getKeys();
    }

    /**
     * Remove the cache and make it unuseable.
     *
     * @throws CacheException
     */
    public static void destroy() throws CacheException {
        try {
            cache.getCacheManager().removeCache(cache.getName());
        } catch (IllegalStateException e) {
            throw new CacheException(e);
        } catch (net.sf.ehcache.CacheException e) {
            throw new CacheException(e);
        }
    }
}
